#include <unistd.h>
#include <stdlib.h>
#include "debug.h"
#include "temp_sample_table.h"
#include "temp_sample.h"
#include "function_interface.h"
#include "utils.h"
#include "fpga_addr_define.h"
#include "table_refresh.h"
#include "debug.h"
#include <pthread.h>
#include <unistd.h>
#include <sys/syscall.h>
#include "misc.h"
#include "syslog.h"


#define IGBT_CHANNEL_PATH       "/sys/devices/platform/ocp/44c00000.interconnect/44c00000.interconnect:segment@200000/44e0d000.target-module/44e0d000.tscadc/TI-am335x-adc.0.auto/igbt_channel"
#define GET_ADC_VALUE           "cat /sys/bus/iio/devices/iio\\:device0/in_voltage0_raw"


typedef struct
{
    uint16_t adSamplePoint[TS_AREA_QTY][TS_POINT_QTY];
    uint16_t adAreaMax[TS_AREA_QTY];
    int16_t tempSamplePoint[TS_AREA_QTY][TS_POINT_QTY];
    int16_t tempAreaMax[TS_AREA_QTY];
    int16_t tempMax;
    uint16_t tempDiffState;
} tempSample_t;
static tempSample_t tempSample = {0};


struct tempSampleTemp_s
{
    int16_t temp;
    int16_t ad;
};
const struct tempSampleTemp_s tempSampleTempTable[] = TEMP_SAMPLE_TEMP_TABLE;
#define TEMP_SAMPLE_TEMP_QTY (sizeof(tempSampleTempTable) / sizeof(struct tempSampleTemp_s))


typedef struct
{
    tempSampleArea_t area;
    tempSamplePoint_t point;
} tempSampleChInfo_t;


struct tempSampleCh_s
{
    uint32_t idxCh;
    tempSampleChInfo_t chInfo;
};
static struct tempSampleCh_s tempSampleChTable[] = TEMP_SAMPLE_CHANNEL_TABLE;
#define TEMP_SAMPLE_CHANNEL_QTY (sizeof(tempSampleChTable) / sizeof(struct tempSampleCh_s))


static int TempSample_GetChannelInfo(uint32_t ch, tempSampleChInfo_t **ppChInfo)
{
    uint32_t idx;

    if(ch < 1 || ch > TEMP_SAMPLE_CHANNEL_QTY)
    {
        PRINT_WARN("Parameter error[%d]", ch);
        return -1;
    }

    for(idx = 0; idx < TEMP_SAMPLE_CHANNEL_QTY; idx++)
    {
        if(tempSampleChTable[idx].idxCh == ch)
        {
            *ppChInfo = &tempSampleChTable[idx].chInfo;
            return 0;
        }
    }

    PRINT_WARN("Get failure[%d]", ch);
    return -2;
}


static int TempSample_Convert(int16_t ad, int16_t *pTemp)
{
    int i;

    if(ad < tempSampleTempTable[0].ad)
    {
        *pTemp = tempSampleTempTable[0].temp;
        PRINT_WARN("Parameter error[%d]", ad);
        return -1;
    }

    if(ad > tempSampleTempTable[TEMP_SAMPLE_TEMP_QTY - 1].ad)
    {
        *pTemp = tempSampleTempTable[TEMP_SAMPLE_TEMP_QTY - 1].temp;
        PRINT_WARN("Parameter error[%d]", ad);
        return -1;
    }

    for(i = 0; i < TEMP_SAMPLE_TEMP_QTY; i++)
    {
        if (ad == tempSampleTempTable[i].ad)
        {
            *pTemp = tempSampleTempTable[i].temp;
            return 0;
        }
        else if ((ad > tempSampleTempTable[i].ad) && (ad < tempSampleTempTable[i + 1].ad))
        {
            *pTemp =  (int)(tempSampleTempTable[i].temp + (ad - tempSampleTempTable[i].ad) / (tempSampleTempTable[i + 1].ad - tempSampleTempTable[i].ad) + 0.5F);
            return 0;
        }
    }

    PRINT_WARN("Convert failure[%d]", ad);
    return -2;
}


static int TempSample_Sample(void)
{
    FILE *fp;
    char set_igbt_channel[200];
    char adc_value[15];
    uint32_t idx, ch;
    int16_t temp;
    tempSampleChInfo_t *pChInfo = NULL, **ppChInfo = &pChInfo;

    for(idx = 0; idx < TEMP_SAMPLE_CHANNEL_QTY; idx++)
    {
        ch = idx + 1;
        sprintf(set_igbt_channel, "echo %d > %s", ch, IGBT_CHANNEL_PATH);
        // PRINT_DEBUG("%s", set_igbt_channel);

        fp = popen(set_igbt_channel, "w");
        if (fp == NULL)
        {
            PRINT_WARN("Popen Write Igbt Channel Error!");
            return -1;
        }

        usleep(100000);
        pclose(fp);

        fp = popen(GET_ADC_VALUE, "r");
        if (fp == NULL)
        {
            PRINT_WARN("Popen Read ADC Error!");
            return -2;
        }

        fread(adc_value, sizeof(char), 15, fp);
        // PRINT_DEBUG("adc_value:%s", adc_value);
        pclose(fp);

        if(TempSample_GetChannelInfo(ch, ppChInfo) != 0)
        {
            return -3;
        }
        tempSample.adSamplePoint[pChInfo->area][pChInfo->point] = atoi(adc_value);
        if(TempSample_Convert(atoi(adc_value), &temp) != 0)
        {
            return -4;
        }
        tempSample.tempSamplePoint[pChInfo->area][pChInfo->point] = temp;

        usleep(150000);
    }

    return 0;
}


static void TempSample_CalculateMaxValue(void)
{
    uint32_t area;
    int16_t tempMax = tempSampleTempTable[0].temp;
    
    for(area = 0; area < TS_AREA_QTY; area++)
    {
        tempSample.adAreaMax[area] = \
            tempSample.adSamplePoint[area][TS_POINT_23] > tempSample.adSamplePoint[area][TS_POINT_14] ? \
            tempSample.adSamplePoint[area][TS_POINT_23] : tempSample.adSamplePoint[area][TS_POINT_14];

        tempSample.tempAreaMax[area] = \
            tempSample.tempSamplePoint[area][TS_POINT_23] > tempSample.tempSamplePoint[area][TS_POINT_14] ? \
            tempSample.tempSamplePoint[area][TS_POINT_23] : tempSample.tempSamplePoint[area][TS_POINT_14];

        tempMax = tempSample.tempAreaMax[area] > tempMax ? \
            tempSample.tempAreaMax[area] : tempMax;
    }

    tempSample.tempMax = tempMax;
}


/**
 * breif 检测同相左右同点位温差
 */
// static void TempSample_CheckTempDiff(void)
// {
//     int16_t tempModuleLeft, tempModuleRight;
//     float tempDiffThre;
//     u16BitType_t tempDiffState;

//     tempDiffState.u16Data = tempSample.tempDiffState;
//     FuncInf_GetArmThrshd(FUNCINF_ARM_THR_TYPE_TEMP_DIFF, &tempDiffThre);
//     PRINT_DEBUG("tempDiffThre[%f]", tempDiffThre);

//     tempModuleLeft = tempSample.tempSamplePoint[TS_AREA_PHASE_A0][TS_POINT_23];
//     tempModuleRight = tempSample.tempSamplePoint[TS_AREA_PHASE_A1][TS_POINT_23];
//     if(abs(tempModuleLeft - tempModuleRight) > (int16_t)tempDiffThre && tempDiffState.bitData.b8 == 0)
//     {
//         tempDiffState.bitData.b0 = 1;
//         tempDiffState.bitData.b8 = 1;
//         //LogInterface_Add(LOG_CLASS_SPECIAL,LOG_MAINTYPE_MISC,10,LDT_TYPE_NONE,NULL);
//         PRINT_DEBUG("Phase A sample point 2/3 temperature differance triggered");
//         syslog(LOG_INFO, "%s: Phase A sample point 2/3 temperature differance triggered(%d %d)", __func__, tempModuleLeft, tempModuleRight);
//     }
//     else if(abs(tempModuleLeft - tempModuleRight) < (int16_t)tempDiffThre - 2 && tempDiffState.bitData.b8 == 1)
//     {
//         tempDiffState.bitData.b0 = 0;
//         tempDiffState.bitData.b8 = 0;
//         //LogInterface_Add(LOG_CLASS_SPECIAL,LOG_MAINTYPE_MISC,11,LDT_TYPE_NONE,NULL);
//         PRINT_DEBUG("Phase A sample point 2/3 temperature differance recovered");
//         syslog(LOG_INFO, "%s: Phase A sample point 2/3 temperature differance recovered", __func__);
//     }

//     tempModuleLeft = tempSample.tempSamplePoint[TS_AREA_PHASE_A0][TS_POINT_14];
//     tempModuleRight = tempSample.tempSamplePoint[TS_AREA_PHASE_A1][TS_POINT_14];
//     if(abs(tempModuleLeft - tempModuleRight) > (int16_t)tempDiffThre && tempDiffState.bitData.b9 == 0)
//     {
//         tempDiffState.bitData.b1 = 1;
//         tempDiffState.bitData.b9 = 1;
//         //LogInterface_Add(LOG_CLASS_SPECIAL,LOG_MAINTYPE_MISC,12,LDT_TYPE_NONE,NULL);
//         PRINT_DEBUG("Phase A sample point 1/4 temperature differance triggered");
//         syslog(LOG_INFO, "%s: Phase A sample point 1/4 temperature differance triggered(%d %d)", __func__, tempModuleLeft, tempModuleRight);
//     }
//     else if(abs(tempModuleLeft - tempModuleRight) < (int16_t)tempDiffThre - 2 && tempDiffState.bitData.b9 == 1)
//     {
//         tempDiffState.bitData.b1 = 0;
//         tempDiffState.bitData.b9 = 0;
//         //LogInterface_Add(LOG_CLASS_SPECIAL,LOG_MAINTYPE_MISC,13,LDT_TYPE_NONE,NULL);
//         PRINT_DEBUG("Phase A sample point 1/4 temperature differance recovered");
//         syslog(LOG_INFO, "%s: Phase A sample point 1/4 temperature differance recovered", __func__);
//     }

//     tempModuleLeft = tempSample.tempSamplePoint[TS_AREA_PHASE_B0][TS_POINT_23];
//     tempModuleRight = tempSample.tempSamplePoint[TS_AREA_PHASE_B1][TS_POINT_23];
//     if(abs(tempModuleLeft - tempModuleRight) > (int16_t)tempDiffThre && tempDiffState.bitData.b10 == 0)
//     {
//         tempDiffState.bitData.b2 = 1;
//         tempDiffState.bitData.b10 = 1;
//         //LogInterface_Add(LOG_CLASS_SPECIAL,LOG_MAINTYPE_MISC,14,LDT_TYPE_NONE,NULL);
//         PRINT_DEBUG("Phase B sample point 2/3 temperature differance triggered");
//         syslog(LOG_INFO, "%s: Phase B sample point 2/3 temperature differance triggered(%d %d)", __func__, tempModuleLeft, tempModuleRight);
//     }
//     else if(abs(tempModuleLeft - tempModuleRight) < (int16_t)tempDiffThre - 2 && tempDiffState.bitData.b10 == 1)
//     {
//         tempDiffState.bitData.b2 = 0;
//         tempDiffState.bitData.b10 = 0;
//         //LogInterface_Add(LOG_CLASS_SPECIAL,LOG_MAINTYPE_MISC,15,LDT_TYPE_NONE,NULL);
//         PRINT_DEBUG("Phase B sample point 2/3 temperature differance recovered");
//         syslog(LOG_INFO, "%s: Phase B sample point 2/3 temperature differance recovered", __func__);
//     }

//     tempModuleLeft = tempSample.tempSamplePoint[TS_AREA_PHASE_B0][TS_POINT_14];
//     tempModuleRight = tempSample.tempSamplePoint[TS_AREA_PHASE_B1][TS_POINT_14];
//     if(abs(tempModuleLeft - tempModuleRight) > (int16_t)tempDiffThre && tempDiffState.bitData.b11 == 0)
//     {
//         tempDiffState.bitData.b3 = 1;
//         tempDiffState.bitData.b11 = 1;
//         //LogInterface_Add(LOG_CLASS_SPECIAL,LOG_MAINTYPE_MISC,16,LDT_TYPE_NONE,NULL);
//         PRINT_DEBUG("Phase B sample point 1/4 temperature differance triggered");
//         syslog(LOG_INFO, "%s: Phase B sample point 1/4 temperature differance triggered(%d %d)", __func__, tempModuleLeft, tempModuleRight);
//     }
//     else if(abs(tempModuleLeft - tempModuleRight) < (int16_t)tempDiffThre - 2 && tempDiffState.bitData.b11 == 1)
//     {
//         tempDiffState.bitData.b3 = 0;
//         tempDiffState.bitData.b11 = 0;
//         //LogInterface_Add(LOG_CLASS_SPECIAL,LOG_MAINTYPE_MISC,17,LDT_TYPE_NONE,NULL);
//         PRINT_DEBUG("Phase B sample point 1/4 temperature differance recovered");
//         syslog(LOG_INFO, "%s: Phase B sample point 1/4 temperature differance recovered", __func__);
//     }

//     tempModuleLeft = tempSample.tempSamplePoint[TS_AREA_PHASE_C0][TS_POINT_23];
//     tempModuleRight = tempSample.tempSamplePoint[TS_AREA_PHASE_C1][TS_POINT_23];
//     if(abs(tempModuleLeft - tempModuleRight) > (int16_t)tempDiffThre && tempDiffState.bitData.b12 == 0)
//     {
//         tempDiffState.bitData.b4 = 1;
//         tempDiffState.bitData.b12 = 1;
//         //LogInterface_Add(LOG_CLASS_SPECIAL,LOG_MAINTYPE_MISC,18,LDT_TYPE_NONE,NULL);
//         PRINT_DEBUG("Phase C sample point 2/3 temperature differance triggered");
//         syslog(LOG_INFO, "%s: Phase C sample point 2/3 temperature differance triggered(%d %d)", __func__, tempModuleLeft, tempModuleRight);
//     }
//     else if(abs(tempModuleLeft - tempModuleRight) < (int16_t)tempDiffThre - 2 && tempDiffState.bitData.b12 == 1)
//     {
//         tempDiffState.bitData.b4 = 0;
//         tempDiffState.bitData.b12 = 0;
//         //LogInterface_Add(LOG_CLASS_SPECIAL,LOG_MAINTYPE_MISC,19,LDT_TYPE_NONE,NULL);
//         PRINT_DEBUG("Phase C sample point 2/3 temperature differance recovered");
//         syslog(LOG_INFO, "%s: Phase C sample point 2/3 temperature differance recovered", __func__);
//     }

//     tempModuleLeft = tempSample.tempSamplePoint[TS_AREA_PHASE_C0][TS_POINT_14];
//     tempModuleRight = tempSample.tempSamplePoint[TS_AREA_PHASE_C1][TS_POINT_14];
//     if(abs(tempModuleLeft - tempModuleRight) > (int16_t)tempDiffThre && tempDiffState.bitData.b13 == 0)
//     {
//         tempDiffState.bitData.b5 = 1;
//         tempDiffState.bitData.b13 = 1;
//         //LogInterface_Add(LOG_CLASS_SPECIAL,LOG_MAINTYPE_MISC,20,LDT_TYPE_NONE,NULL);
//         PRINT_DEBUG("Phase C sample point 1/4 temperature differance triggered");
//         syslog(LOG_INFO, "%s: Phase C sample point 1/4 temperature differance triggered(%d %d)", __func__, tempModuleLeft, tempModuleRight);
//     }
//     else if(abs(tempModuleLeft - tempModuleRight) < (int16_t)tempDiffThre - 2 && tempDiffState.bitData.b13 == 1)
//     {
//         tempDiffState.bitData.b5 = 0;
//         tempDiffState.bitData.b13 = 0;
//         //LogInterface_Add(LOG_CLASS_SPECIAL,LOG_MAINTYPE_MISC,21,LDT_TYPE_NONE,NULL);
//         PRINT_DEBUG("Phase C sample point 1/4 temperature differance recovered");
//         syslog(LOG_INFO, "%s: Phase C sample point 1/4 temperature differance recovered", __func__);
//     }

//     tempSample.tempDiffState = tempDiffState.u16Data;
// }


static int TempSample_HandleMisc(void)
{
    uint32_t idxPhase;
    int16_t adValue;

    for(idxPhase = 0; idxPhase < 3; idxPhase++)
    {
        adValue = tempSample.adAreaMax[idxPhase] > tempSample.adAreaMax[idxPhase + 3] ? \
            tempSample.adAreaMax[idxPhase] : tempSample.adAreaMax[idxPhase + 3];
        if(FuncInf_DirectWriteFpga(FUNCINF_OPERATOR_TEMP_SAMPLE, FPGA_ADDR_220 + idxPhase, adValue) != FUNCINF_ERR_NONE)
        {
            PRINT_WARN("Synchronize to FPGA failure");
            return -1;
        }
    }

    return 0;
}


void __attribute__((weak)) TempSample_PrintAllInfo(void)
{
    uint16_t area, point;

    for(area = 0; area < TS_AREA_QTY; area++)
    {
        for(point = 0; point < TS_POINT_QTY; point++)
        {
            PRINT_DEBUG("area%d point%d: ad[%d] temp[%d]", \
                area, point, tempSample.adSamplePoint[area][point], tempSample.tempSamplePoint[area][point]);
        }
        PRINT_DEBUG();
    }
    PRINT_DEBUG();    
}


void TempSample_Thread(void *pPara)
{
    Misc_InitThread(__func__);

    int err = 0;

    while(1)
    {
        if((err = TempSample_Sample()) != 0)
        {
            PRINT_WARN("Sample failure[%d]", err);
        }

        TempSample_CalculateMaxValue();

        // TempSample_CheckTempDiff(); /* 已在过温模块中实现 */

        if((err = TempSample_HandleMisc()) != 0)
        {
            PRINT_WARN("Handler misc failure[%d]", err);
        }
        
        // TempSample_PrintAllInfo();
        TableRefresh_SendMessage(TABLE_MSGVAL_TEMP);
    }
}


int TempSample_GetSamplePointAdValue(tempSampleArea_t area, tempSamplePoint_t point, uint16_t *pAdValue)
{
    if(area >= TS_AREA_QTY || point >= TS_POINT_QTY)
    {
        PRINT_WARN("Parameter error[%d][%d]", area, point);
        return -1;
    }

    *pAdValue = tempSample.adSamplePoint[area][point];
    // PRINT_DEBUG("%d", *pAdValue);

    return 0;
}


int TempSample_GetSamplePointTemperature(tempSampleArea_t area, tempSamplePoint_t point, int16_t *pTemp)
{
    if(area >= TS_AREA_QTY || point >= TS_POINT_QTY)
    {
        PRINT_WARN("Parameter error[%d][%d]", area, point);
        return -1;
    }

    *pTemp = tempSample.tempSamplePoint[area][point];
    // PRINT_DEBUG("%d", *pTemp);

    return 0;
}


int TempSample_GetTemperature(tempSampleArea_t area, int16_t *pTemp)
{
    if(area >= TS_AREA_QTY)
    {
        PRINT_WARN("Parameter error[%d]", area);
        return -1;
    }

    *pTemp = tempSample.tempAreaMax[area];
    // PRINT_DEBUG("%d", *pTemp);

    return 0;
}


int TempSample_GetMaxTemperature(int16_t *pTemp)
{
    *pTemp = tempSample.tempMax;
    // PRINT_DEBUG("%d", *pTemp);

    return 0;
}

